package com.et.machine.util

import java.io.Serializable
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.PriorityBlockingQueue
import kotlin.collections.HashMap


class TaskManager private constructor() {
    private val THREAD_SIZE = 3
    private val mTaskQueue: TaskQueue = TaskQueue(THREAD_SIZE)
    fun addTask(taskBase: TaskBase): Boolean {
        return mTaskQueue.addTask(taskBase)
    }

    fun retryTask(taskBase: TaskBase): Boolean {
        return mTaskQueue.retry(taskBase)
    }

    fun cancelTask(taskBase: TaskBase): Boolean {
        return mTaskQueue.remove(taskBase)
    }

    fun start() {
        mTaskQueue.start()
    }

    fun stop() {
        mTaskQueue.stop()
    }

    companion object {
        private var mTaskManager: TaskManager? = null

        @get:Synchronized
        val instance: TaskManager?
            get() {
                if (mTaskManager == null) {
                    mTaskManager = TaskManager()
                }
                return mTaskManager
            }
    }

}

abstract class TaskBase(var code: String, var string: String) : Serializable,
    Comparable<Any?> {
    var priority: Int = 0
    abstract fun taskExc()
    override fun compareTo(other: Any?): Int {
        val taskBase = other as TaskBase?
        if (priority > taskBase!!.priority) {
            return -1
        } else if (priority < taskBase.priority) {
            return 1
        }
        return 0
    }
}

private val mWaitMap = HashMap<String, MutableList<TaskBase>>()

class TaskQueue(threadSize: Int) {
    private val QUEUE_SIZE = 20 //任务队列大小
    private val mWaitList: MutableList<TaskBase> = ArrayList()
    private val mTaskQueue: PriorityBlockingQueue<TaskBase> =
        PriorityBlockingQueue<TaskBase>(QUEUE_SIZE)
    private val mThreadPool: ExecutorService = Executors.newFixedThreadPool(threadSize)
    private val mAddThread: ExecutorService = Executors.newSingleThreadExecutor()
    private val mThreadSize: Int = threadSize
    fun start() {
        for (i in 0 until mThreadSize) {
            mThreadPool.execute(TaskDispatcher(mTaskQueue))
        }
        mAddThread.execute(TaskAddDispatcher(mWaitList, mTaskQueue))
    }

    fun stop() {
        if (!mThreadPool.isShutdown) {
            mThreadPool.shutdown()
        }
    }

    fun addTask(taskBase: TaskBase): Boolean {
        synchronized(mWaitList) {
            mWaitMap[taskBase.code] = mutableListOf(taskBase)
            mWaitMap[taskBase.code]?.forEach {
                mWaitList.add(it)
            }
            return true
        }
    }

    fun retry(taskBase: TaskBase): Boolean {
        synchronized(mWaitList) {
            if (taskBase.priority > 3) {
                remove(taskBase)
                return false
            } else return when (taskBase.code) {
                "51", "61", "62", "63", "64", "11", "81" -> {
                    addTask(taskBase)
                    return true
                }
                "13" -> {
                    if (mWaitMap[taskBase.code] != null) {
                        val updateMap = HashMap<String, String>()
                        mWaitMap[taskBase.code]?.forEach {
                            val count = it.string.substring(37, 40).toInt()
                            for (index in 0 until count) {
                                updateMap[it.string.substring(
                                    40 + (index * 34),
                                    44 + (index * 34)
                                )] =
                                    it.string.substring(40 + (index * 34), 74 + (index * 34))
                            }
                        }
                        mWaitMap[taskBase.code] = mutableListOf()

                        var count = 1
                        val goodsInfo = StringBuilder().apply { append("000") }
                        updateMap.forEach {
                            goodsInfo.replace(0, 3, String.format("%03d", count))
                            goodsInfo.append(it.value)
                            count++
                            if (count >= 28) {
                                count = 1
                                mWaitMap[taskBase.code]?.add(taskBase.apply {
                                    string = string.substring(0, 37) + goodsInfo.toString()
                                })
                                goodsInfo.clear()
                            }
                        }
                    } else {
                        mWaitMap[taskBase.code] = mutableListOf(taskBase)
                    }
                    mWaitMap[taskBase.code]?.forEach {
                        mWaitList.add(it)
                    }
                    return true
                }
                "12" -> addTask(taskBase)
                else -> false
            }
        }
    }

    fun remove(taskBase: TaskBase): Boolean {
        synchronized(mWaitList) {
            mWaitMap.remove(taskBase.code)
            return mWaitList.remove(taskBase)
        }
    }

}

class TaskAddDispatcher(
    private val mWaitList: MutableList<TaskBase>,
    private val mTaskQueue: PriorityBlockingQueue<TaskBase>
) : Thread() {
    override fun run() {
        while (true) {
            if (mWaitList.isNotEmpty()) {
                synchronized(mWaitList) {
                    val taskBase = mWaitList.removeAt(0)
                    mWaitMap.remove(taskBase.code)
                    mTaskQueue.add(taskBase)
                }
            } else {
                try {
                    sleep(2000)
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
            }
        }
    }
}

class TaskDispatcher(private val mTaskQueue: PriorityBlockingQueue<TaskBase>) : Thread() {
    override fun run() {
        while (true) {
            try {
                val task = mTaskQueue.take()
                task!!.taskExc()
            } catch (e: InterruptedException) {
                e.printStackTrace()
                continue
            }
        }
    }
}